package com.graduation_design.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.graduation_design.common.dto.AppOrderDto;
import com.graduation_design.entity.*;
import com.graduation_design.mapper.AppCartItemMapper;
import com.graduation_design.mapper.AppRefundMapper;
import com.graduation_design.modules.app.mq.CancelOrderSender;
import com.graduation_design.service.*;
import com.graduation_design.mapper.AppOrderMapper;
import com.graduation_design.utils.KdApiUtil;
import com.graduation_design.utils.ShiroUtil;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
* @author 从南
* @description 针对表【app_order】的数据库操作Service实现
* @createDate 2024-02-16 18:15:58
*/
@Service
public class AppOrderServiceImpl extends ServiceImpl<AppOrderMapper, AppOrder>
    implements AppOrderService{

    @Resource
    AppUserService appUserService;

    @Resource
    AppAddressService appAddressService;

    @Resource
    AppCartItemMapper appCartItemMapper;

    @Resource
    AppCartItemService appCartItemService;

    @Resource
    AppOrderItemService appOrderItemService;

    @Resource
    AppSkuStockService appSkuStockService;

    @Resource
    CancelOrderSender cancelOrderSender;

    @Resource
    AppRefundMapper appRefundMapper;

    @Resource
    AppProductService appProductService;

    @Resource
    AppOrderMapper appOrderMapper;

    /**
     * 购物车购买、立即购买的订单预览
     * @param orderDto
     * @return
     */
    @Override
    public Object preview(AppOrderDto orderDto) {

        // 购物车购买cartIds不为空，立即购买productId不为空！不能同时为空
        // 同时不为空的情况，按照购物车购买为标准。
        Assert.isTrue((orderDto.getCartIds() != null && orderDto.getCartIds().size() > 0)
                || (orderDto.getProductId() != null && orderDto.getSkuId() != null && orderDto.getQuantity() != null) ,
                "参数不完整");

        System.out.println(orderDto.toString());

        long userId = appUserService.getCurrentUserId();

        // 获取收货地址
        AppAddress address;
        // addressId为空，则展示默认收货地址，如果没有默认收货地址，则不展示
        if (orderDto.getAddressId() == null) {
            address = appAddressService.getDefault(userId);
        } else {
            // 不为空，根据id获取收货地址
            address = appAddressService.getById(orderDto.getAddressId());
            Assert.isTrue(address != null && address.getUserId() == userId, "配送地址异常");
        }

        // 获取购物车信息
        List<AppCartItem> cartItems = getCartItemsByOrderDto(userId, orderDto);

        // 计算总金额，价格、数量
        BigDecimal total = cartItems.stream()
                .map(item -> item.getPrice().multiply(new BigDecimal(item.getQuantity())))
                .reduce(BigDecimal.ZERO, BigDecimal::add);

        // 计算运费
        BigDecimal freight = new BigDecimal("0");
        total = total.add(freight);

        return MapUtil.builder()
                .put("address", address)
                .put("cartItems", cartItems)
                .put("total", total)
                .put("freight", freight)
                .build();
    }

    /**
     * 创建订单
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Object create(AppOrderDto orderDto) {

        AppUser appUser = appUserService.getCurrentUser();
        Long userId = appUser.getId();

        // 判断收货地址
        AppAddress address = appAddressService.getById(orderDto.getAddressId());
        Assert.isTrue(address != null && address.getUserId() == userId, "配送地址异常");

        // 获取购物车信息
        List<AppCartItem> cartItems = getCartItemsByOrderDto(userId, orderDto);

        // 计算总金额，价格、数量
        BigDecimal total = cartItems.stream()
                .map(item -> item.getPrice().multiply(new BigDecimal(item.getQuantity())))
                .reduce(BigDecimal.ZERO, BigDecimal::add);

        // 计算运费
        BigDecimal freight = new BigDecimal("0");
        total = total.add(freight);

        // 创建订单记录
        AppOrder appOrder = new AppOrder();
        appOrder.setUserId(userId);
        appOrder.setSn(generateOrderSn());

        appOrder.setFreight(freight);
        appOrder.setTotalAmount(total);

        // 收货人
        appOrder.setReceiverName(address.getName());
        appOrder.setReceiverTel(address.getTel());
        appOrder.setReceiverAddress(address.getAddress());
        appOrder.setReceiverPostalCode(address.getPostalCode());
        appOrder.setReceiverAreaCode(address.getAreaCode());

        // 订单各种状态
        appOrder.setOrderStatus(0);

        appOrder.setIsDelete(false);
        appOrder.setCreated(LocalDateTime.now());
        appOrder.setNote(orderDto.getNote());

        this.save(appOrder);

        // 保存商品信息快照
        List<AppOrderItem> orderItems = new ArrayList<>();
        for (AppCartItem cartItem : cartItems) {

            AppOrderItem orderItem = new AppOrderItem();
            orderItem.setProductId(cartItem.getProductId());
            orderItem.setProductName(cartItem.getProductName());
            orderItem.setProductImage(cartItem.getProductImage());
            orderItem.setProductSn(cartItem.getProductSn());
            orderItem.setCategoryId(cartItem.getCategoryId());
            orderItem.setPrice(cartItem.getPrice());
            orderItem.setQuantity(cartItem.getQuantity());

            orderItem.setSkuId(cartItem.getSkuId());
            orderItem.setSku(cartItem.getSku());

            orderItem.setOrderId(appOrder.getId());
            orderItem.setCreated(LocalDateTime.now());

            orderItems.add(orderItem);
        }

        appOrderItemService.saveBatch(orderItems);

        // 删除购物车中的商品
        if (orderDto.getCartIds() != null && orderDto.getCartIds().size() > 0) {
            appCartItemService.remove(new QueryWrapper<AppCartItem>()
                    .eq("user_id", userId)
                    .in("id", orderDto.getCartIds())
            );
        }

        // 判断库存并扣减库存
        appSkuStockService.reduceStock(orderItems);

        // 添加订单到超期任务队列，30分钟 - 死信队列
        cancelOrderSender.sendMessage(appOrder.getId(), 30 * 60 * 1000);

        return appOrder.getSn();
    }

    /**
     * 判断订单是否存在
     */
    @Override
    public AppOrder getBySn(String sn) {
        AppOrder appOrder = this.getOne(new QueryWrapper<AppOrder>().eq("sn", sn));
        Assert.notNull(appOrder, "订单不存在");
        return appOrder;
    }

    @Override
    public AppOrder getOwnBySn(String sn) {

        AppOrder appOrder = getBySn(sn);
        long userId = appUserService.getCurrentUserId();
        Assert.isTrue(userId == appOrder.getUserId(), "无权限操作该订单");
        return appOrder;
    }

    @Override
    public AppOrder getOwnById(Long id) {
        AppOrder appOrder = this.getById(id);
        long userId = appUserService.getCurrentUserId();
        Assert.isTrue(userId == appOrder.getUserId(), "无权限操作该订单");
        return appOrder;
    }

    /**
     * 订单计数
     */
    @Override
    public Object getOrderCount() {
        long userId = appUserService.getCurrentUserId();
        // 订单状态：0->待付款；1->待发货；2->待收货；3-已完成；4->已取消；5-申请退款，6->已退款，7->退款失败
        List<AppOrder> appOrders = this.list(new QueryWrapper<AppOrder>().eq("user_id", userId));
        int unPay = 0;
        int unDeli = 0;
        int unRecv = 0;
        int unRefund = 0;

        long unComment = 0;

        for (AppOrder appOrder : appOrders) {
            if (appOrder.getOrderStatus() == 0) {
                unPay++;
            } else if (appOrder.getOrderStatus() == 1) {
                unDeli++;
            } else if (appOrder.getOrderStatus() == 2) {
                unRecv++;
            }else if (appOrder.getOrderStatus() == 5) {
                unRefund++;
            }
        }
        List<Long> orderIds = appOrders.stream().filter(e -> e.getOrderStatus() == 3)
                .map(AppOrder::getId).collect(Collectors.toList());
        if (!orderIds.isEmpty()) {
            unComment = appOrderItemService.count(new QueryWrapper<AppOrderItem>().in("order_id", orderIds)
                    .isNull("comment_id")
            );
        }
        return MapUtil.builder()
                .put("unPay", unPay)
                .put("unDeli", unDeli)
                .put("unRecv", unRecv)
                .put("unRefund", unRefund)
                .put("unComment", unComment)
                .build();
    }

    /**
     * 分页
     */
    @Override
    public Object getPage(Page page, long userId, Integer status) {

        Page<AppOrder> pageData = this.page(page, new QueryWrapper<AppOrder>()
                .eq("user_id", userId)
                .eq(status != null, "order_status", status)
                .orderByDesc("created")
        );

        for (AppOrder appOrder : pageData.getRecords()) {
            List<AppOrderItem> appOrderItems = appOrderItemService.listByOrderId(appOrder.getId());
            appOrder.setOrderItems(appOrderItems);
        }

        return pageData;
    }

    /**
     * 订单详情
     */
    @Override
    public Object detail(Long id) {
        AppOrder appOrder = this.getOwnById(id);

        List<AppOrderItem> appOrderItems = appOrderItemService.listByOrderId(id);
        appOrder.setOrderItems(appOrderItems);

        if (Arrays.asList(5, 6).contains(appOrder.getOrderStatus())) {
            // 退款单
            AppRefund appRefund = appRefundMapper.selectOne(new QueryWrapper<AppRefund>().eq("order_id", id));
            appOrder.setAppRefund(appRefund);
        }

        return appOrder;
    }

    /**
     * 订单取消
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Object cancel(Long id) {
        AppOrder appOrder = this.getOwnById(id);

        // 1. 判断是否能取消
        Assert.isTrue(appOrder.getOrderStatus() == 0, "无法取消该订单");

        // 2. 解放商品库存
        appSkuStockService.releaseStock(appOrder);

        // 3. 设置订单状态、订单结束时间endTime
        appOrder.setOrderStatus(4);
        appOrder.setCompleteTime(LocalDateTime.now());
        appOrder.setUpdated(LocalDateTime.now());
        return this.updateById(appOrder);
    }

    /**
     * 删除订单
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Object delete(Long id) {
        AppOrder appOrder = this.getOwnById(id);
        // 1. 判断是否能删除
        Assert.isTrue(Arrays.asList(0, 3, 4, 6).contains(appOrder.getOrderStatus()), "无法删除该订单");

        // 待付款订单
        if (appOrder.getOrderStatus() == 0) {
            // 1. 未取消先取消再删除
            appOrder.setOrderStatus(4);
            appOrder.setCompleteTime(LocalDateTime.now());
            // 2. 解放商品库存
            appSkuStockService.releaseStock(appOrder);
        }

        appOrder.setUpdated(LocalDateTime.now());
        return this.removeById(appOrder);
    }

    /**
     * 订单物流
     */
    @Override
    public Object getDeliveryInfo(AppOrder appOrder) throws Exception {
        String deliveryInfo = new KdApiUtil().getDeliveryInfo(appOrder.getDeliveryCompany(), appOrder.getDeliverySn());

        JSONArray traces = JSONUtil.parseObj(deliveryInfo).getJSONArray("Traces");

        List<Map<Object, Object>> list = traces.stream().map(e -> {
            JSONObject obj = JSONUtil.parseObj(e);
            return MapUtil.builder()
                    .put("acceptTime", obj.getStr("AcceptTime"))
                    .put("acceptStation", obj.getStr("AcceptStation"))
                    .put("remark", obj.getStr("Remark"))
                    .build();
        }).collect(Collectors.toList());

        return list;
    }

    /**
     * 确认收货
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void confirm(Long id) {
        AppOrder appOrder = this.getOwnById(id);

        // 1. 判断是否能确认收货
        Assert.isTrue(appOrder.getOrderStatus() == 2, "该订单无法确认收货");

        // 2、更新商品销量
        this.updateProductSales(appOrder.getId());
        // 3、确认收货状态
        appOrder.setOrderStatus(3);
        appOrder.setReceiveTime(LocalDateTime.now());
        appOrder.setUpdated(LocalDateTime.now());
        this.updateById(appOrder);
    }

    @Override
    public Object pageAdmin(Page page, AppOrder appOrder) {
        return appOrderMapper.pageWithUsername(page, appOrder);
    }

    @Override
    public Object getOrderInfo(Long id) {
        AppOrder appOrder = this.getById(id);
        Assert.notNull(appOrder, "订单不存在");

        appOrder.setOrderItems(appOrderItemService.listByOrderId(id));

        AppUser appUser = appUserService.getById(appOrder.getUserId());
        appOrder.setUsername(appUser.getUsername());
        appOrder.setUserAvatar(appUser.getAvatar());

        AppRefund appRefund = appRefundMapper.selectOne(new QueryWrapper<AppRefund>().eq("order_id", id));
        appOrder.setAppRefund(appRefund);

        return appOrder;
    }

    /**
     * 发货
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void shipAdmin(AppOrder appOrder) {

        AppOrder order = this.getById(appOrder.getId());
        Assert.notNull(order, "订单不存在");
        Assert.isTrue(order.getOrderStatus() == 1, "该订单状态不允许发货");
        Assert.isTrue(appOrder.getDeliverySn() != null && appOrder.getDeliveryCompany() != null, "物流公司、运单号不能为空");

        order.setDeliveryCompany(appOrder.getDeliveryCompany());
        order.setDeliverySn(appOrder.getDeliverySn());
        order.setDeliveryTime(LocalDateTime.now());
        order.setOrderStatus(2);
        order.setUpdated(LocalDateTime.now());

        Long adminId = ShiroUtil.getProfile().getId();
        order.setAdminNote("管理员" + adminId + "：发货；" + order.getAdminNote());

        this.updateById(order);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void closeAdmin(Long id, String note, Long adminId) {
        AppOrder order = this.getById(id);
        Assert.notNull(order, "订单不存在");
        Assert.notNull(adminId, "管理员不能为空");
        Assert.hasLength(note, "订单关闭理由不能为空");
        Assert.isTrue(order.getOrderStatus() == 0, "该订单状态不允许关闭");

        order.setOrderStatus(4);
        order.setUpdated(LocalDateTime.now());

        note = "管理员" + adminId + "：" + note;
        order.setAdminNote(order.getAdminNote() == null ? note : note + " - " + order.getAdminNote());
        this.updateById(order);

        // 释放库存等
        appSkuStockService.releaseStock(order);
    }

    /**
     * 更新商品销量
     */
    private void updateProductSales(Long orderId) {
        List<AppProduct> products = new ArrayList<>();
        List<AppOrderItem> orderItems = appOrderItemService.listByOrderId(orderId);
        orderItems.forEach(item -> {
            AppProduct product = appProductService.getById(item.getProductId());
            product.setSale(product.getSale() + item.getQuantity());
            products.add(product);
        });
        appProductService.updateBatchById(products);
    }

    private String generateOrderSn() {
        String dateStr = DateUtil.format(new Date(), "yyMMddHHmm");
        return "D" + dateStr + RandomUtil.randomNumbers(4);
    }

    /**
     * 购买预览获取信息
     */
    private List<AppCartItem> getCartItemsByOrderDto(long userId, AppOrderDto orderDto) {

        List<AppCartItem> cartItems;
        if (orderDto.getCartIds() != null && orderDto.getCartIds().size() > 0) {
            // 购物车购买
            cartItems = appCartItemMapper.getCartItemsWithProductInfo(new QueryWrapper<AppCartItem>()
                    .eq("user_id", userId)
                    .in("c.id", orderDto.getCartIds())
                    .orderByDesc("created")
            );
        } else {
            // 立即购买
            AppCartItem cartItem = appCartItemService.getCombinedCartItems(userId, orderDto.getProductId(), orderDto.getSkuId(), orderDto.getQuantity());
            cartItems = new ArrayList<>();
            cartItems.add(cartItem);
        }

        return cartItems;
    }
}




